/*
* Copyright 2010 Pavel Kozhin 
*
* Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. 
* You may obtain a copy of the License at 
* 
* http://www.apache.org/licenses/LICENSE-2.0
* 
* Unless required by applicable law or agreed to in writing, software 
* distributed  under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License.
*
* Author: Pavel Kozhin.
*/

package org.etherframework.wire.wirings
{
	import flash.events.Event;
	import flash.utils.Dictionary;
	
	import org.etherframework.core.Access;
	import org.etherframework.core.DomainAccess;
	import org.etherframework.core.IBridgeInteraction;
	import org.etherframework.reflection.Metadata;
	import org.etherframework.reflection.MetadataMember;
	import org.etherframework.reflection.Method;
	import org.etherframework.wire.WiringData;

	public final class Unwired implements IWiring, IInjection
	{
		public var member:Object;
		
		private var metadatas:Array;
		
		private var bridgeInteraction:IBridgeInteraction;
		
		private var dictionary:Dictionary;
		
		private var name:String;
		
		public function wire(name:String, target:Object, item:Object, data:WiringData):Boolean
		{
			if (!name || !target || !item || !data)
				throw new ArgumentError("Parameters can not be empty or null.");
			
			if (!(item is Method))
				throw new ArgumentError("Unwired metatag can be applied only to method.");
			
			var member:MetadataMember = item as MetadataMember;
			metadatas = member.metadata;
			this.name = name;
			this.member = (member.uri) ? 
				new QName(new Namespace(member.uri), member.name) : member.name;
			bridgeInteraction = data.bridge.interaction;
			bridgeInteraction.listenItemUnwired(target, itemUnwiredHandler, Access.LOCAL, DomainAccess.SINGLE);
			dictionary = new Dictionary(true);
			dictionary[target] = true;
			
			return true;
		}
		
		public function unwire(target:Object):Boolean
		{
			var target:Object = getTarget();
			
			if (target)
			{
				bridgeInteraction.unlistenItemUnwired(getTarget(), itemUnwiredHandler, Access.LOCAL, DomainAccess.SINGLE);
			}
			
			bridgeInteraction = null;
			member = null;
			metadatas = null;
			dictionary = null;
			name = null;
			return true;
		}
		
		public function inject(name:String, target:Object, data:WiringData):Boolean
		{
			if (!(target[member] is Function))
				throw new ArgumentError("Wired can be applied only to method");
				
			target[member].apply();
			return true;
		}
		
		private function itemUnwiredHandler(event:Event):void
		{
			var target:Object = getTarget();
			
			if (target)
			{
				bridgeInteraction.unlistenItemUnwired(target, itemUnwiredHandler, Access.LOCAL, DomainAccess.SINGLE);
				
				for each (var metadata:Metadata in metadatas)
				{
					if (metadata.name == name)
					{
						target[member].apply();
						break;
					}
				}
			}
		}
		
		private function getTarget():Object
		{
			for (var target:Object in dictionary){}
			
			if (!target)
				trace("Unwired: target is missing.");
			
			return target;
		}
	}
}
